/**
 * Copyright 2018 人人开源 http://www.renren.io
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package pay.utils;


import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
import pay.exception.RRException;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * 日期处理
 *
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2016年12月21日 下午12:53:33
 */
public class DateUtils {
    /**
     * 时间格式(yyyy-MM-dd)
     */
    public final static String DATE_PATTERN = "yyyy/MM/dd";
    /**
     * 时间格式(yyyy/MM/dd HH:mm:ss)
     */
    public final static String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss";

    /**
     * 时间格式(yyyy/MM/dd HH:mm:ss)
     */
    public final static String DATE_TIME_SECOND_PATTERN = "yyyy/MM/dd HH:mm:ss.SSS";

    public final static String WX_DATE_PATTERN = "yyyyMMddHHmmss";

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param dateStr 日期
     * @return 返回yyyy-MM-dd格式日期
     */
    public static Date parse(String dateStr, String pattern) {
        if (StringUtils.isNotBlank(dateStr)) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            try {
                return df.parse(dateStr);
            } catch (ParseException e) {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date 日期
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date    日期
     * @param pattern 格式，如：DateUtils.DATE_TIME_PATTERN
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date, String pattern) {
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.format(date);
        }
        return null;
    }

//    /**
//     * 字符串转换成日期
//     *
//     * @param strDate 日期字符串
//     * @param pattern 日期的格式，如：DateUtils.DATE_TIME_PATTERN
//     */
//    public static Date stringToDate(String strDate, String pattern) {
//        if (StringUtils.isBlank(strDate)) {
//            return null;
//        }
//
//        DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
//        return fmt.parseLocalDateTime(strDate).toDate();
//    }

    /**
     * 根据周数，获取开始日期、结束日期
     *
     * @param week 周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return 返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekStartAndEnd(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date beginDate = date.toDate();
        Date endDate = date.plusDays(6).toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 对日期的【秒】进行加/减
     *
     * @param date    日期
     * @param seconds 秒数，负数为减
     * @return 加/减几秒后的日期
     */
    public static Date addDateSeconds(Date date, int seconds) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusSeconds(seconds).toDate();
    }

    /**
     * 对日期的【分钟】进行加/减
     *
     * @param date    日期
     * @param minutes 分钟数，负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addDateMinutes(Date date, int minutes) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对日期的【小时】进行加/减
     *
     * @param date  日期
     * @param hours 小时数，负数为减
     * @return 加/减几小时后的日期
     */
    public static Date addDateHours(Date date, int hours) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusHours(hours).toDate();
    }

    /**
     * 对日期的【天】进行加/减
     *
     * @param date 日期
     * @param days 天数，负数为减
     * @return 加/减几天后的日期
     */
    public static Date addDateDays(Date date, int days) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusDays(days).toDate();
    }

    /**
     * 对日期的【周】进行加/减
     *
     * @param date  日期
     * @param weeks 周数，负数为减
     * @return 加/减几周后的日期
     */
    public static Date addDateWeeks(Date date, int weeks) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusWeeks(weeks).toDate();
    }

    /**
     * 对日期的【月】进行加/减
     *
     * @param date   日期
     * @param months 月数，负数为减
     * @return 加/减几月后的日期
     */
    public static Date addDateMonths(Date date, int months) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMonths(months).toDate();
    }

    /**
     * 对日期的【年】进行加/减
     *
     * @param date  日期
     * @param years 年数，负数为减
     * @return 加/减几年后的日期
     */
    public static Date addDateYears(Date date, int years) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusYears(years).toDate();
    }

    /**
     * 比较日期的年月日大小，date1小于date2返回-1， date1大于date2返回1， date1等于date2返回0
     *
     * @param date1
     * @param date2
     * @return
     * @throws ParseException
     */
    public static int compareDay(Date date1, Date date2) throws ParseException {
        DateFormat df = new SimpleDateFormat(DATE_PATTERN);
        date1 = df.parse(df.format(date1));
        date2 = df.parse(df.format(date2));
        if (date1.getTime() < date2.getTime()) {
            return -1;
        } else if (date1.getTime() > date2.getTime()) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * 获取月的第一天和最后一天
     *
     * @param i 0为本月，1为下月，-1为上月
     * @return
     */
    public static Date[] getMonthStartAndEnd(int i) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusMonths(i));
        Date beginDate = date.dayOfMonth().withMinimumValue().toDate();
        Date endDate = date.dayOfMonth().withMaximumValue().toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 获取本月的最后一天23:59:59
     *
     * @return
     */
    public static Date getMonthEndTimeJoda() {
        DateTime now = new DateTime();
        DateTime endOfMonth = now.dayOfMonth().withMaximumValue()
                .withHourOfDay(23)
                .withMinuteOfHour(59)
                .withSecondOfMinute(59)
                .withMillisOfSecond(999);
        return endOfMonth.toDate();
    }


    /**
     * 获取一个月的日期字符集合
     *
     * @param i 0为本月，1为下月，-1为上月
     * @return
     */
    public static List<String> getDaysOfMonth(int i) {
        List<String> dayOfMonthList = new ArrayList<>();
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusMonths(i));
        Date beginDate = date.dayOfMonth().withMinimumValue().toDate();
        Date endDate = date.dayOfMonth().withMaximumValue().toDate();
        int dd = Integer.parseInt(format(endDate, "dd"));
        for (int j = 0; j < dd; j++) {
            Date day = addDateDays(beginDate, j);
            dayOfMonthList.add(format(day, DATE_PATTERN));
        }
        return dayOfMonthList;
    }

    /**
     * 获取一个周的日期字符集合
     *
     * @param i 0为本周，1为下周，-1为上周
     * @return
     */
    public static List<String> getDaysOfWeek(int i) {
        List<String> dayOfWeekList = new ArrayList<>();
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusMonths(i));
        Date beginDate = date.dayOfWeek().withMinimumValue().toDate();
        for (int j = 0; j < 7; j++) {
            Date day = addDateDays(beginDate, j);
            dayOfWeekList.add(format(day, DATE_PATTERN));
        }
        return dayOfWeekList;
    }

    /**
     * 获取一年的月份字符集合
     *
     * @param i 0为本年，1为下年，-1为去年
     * @return
     */
    public static List<String> getMonthsOfYear(int i) {
        List<String> monsOfYearList = new ArrayList<>();
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusYears(i));
        Date beginDate = date.dayOfYear().withMinimumValue().toDate();
        for (int j = 0; j < 12; j++) {
            Date day = addDateMonths(beginDate, j);
            monsOfYearList.add(format(day, "yyyy-MM"));
        }
        return monsOfYearList;
    }

    /**
     * 获取自定义时间区间的日期字符串集合
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<String> getDaysOfCustom(Date startDate, Date endDate) {
        if (startDate == null || endDate == null) {
            throw new RRException("时间参数异常");
        }
        List<String> dayOfWeekList = new ArrayList<>();

        Date day = startDate;
        for (int j = 0; day.getTime() < endDate.getTime(); j++) {
            day = addDateDays(startDate, j);
            dayOfWeekList.add(format(day, DATE_PATTERN));
        }
        return dayOfWeekList;
    }


    /**
     * 判断两个时间段是否有交集（时间段有重叠）
     *
     * @param startDate1 时间段1开始时间
     * @param endDate1   时间段1结束时间
     * @param startDate2 时间段2开始时间
     * @param endDate2   时间段2结束时间
     * @return
     */
    public static boolean twoDateRangeBeMixed(Date startDate1, Date endDate1, Date startDate2, Date endDate2) {
        if (endDate2.before(startDate1) || startDate2.after(endDate1)) {
            //不重叠
            return false;
        } else {
            return true;
        }
    }

    public static Integer getDaysBetweenDate(Date startDate, Date endDate) {
        System.out.println(endDate.getTime() - startDate.getTime());
        return (int) (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24);
    }

    /**
     * 获取本周所有天数
     *
     * @return
     */
    public static List<String> getWeekDaysList() {
        java.time.LocalDate today = java.time.LocalDate.now();
        java.time.LocalDate monday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        java.time.LocalDate sunday = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        List<String> weekDates = new ArrayList<>();
        while (!monday.isAfter(sunday)) {
            weekDates.add(monday.toString());
            monday = monday.plusDays(1);
        }
        return weekDates;
    }

    /**
     * 获取年月
     *
     * @param n 想要获取的数量
     * @return
     */
    public static List<String> getRecentMonths(int n) {
        List<String> months = new ArrayList<>();
        LocalDate now = LocalDate.now();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        for (int i = 0; i < n; i++) {
            months.add(sdf.format(now.minusMonths(i).toDate()));
        }
        Collections.reverse(months);
        return months;
    }

    //获取当前时间6月之前月份字符串
    private List<String> getSixMonthAgo() {
        List<String> months = new ArrayList<>();
        for (int i = 5; i >= 0; i--) {
            Calendar calendar = Calendar.getInstance();
            // 将日历回退到上一个月
            calendar.add(Calendar.MONTH, -i);
            // 获取并格式化月份
            String month = String.format("%tY-%tm", calendar, calendar);
            months.add(month);
        }
        return months;
    }

    /**
     * 本周日期
     *
     * @return
     * @throws ParseException
     */
    private static List<String> getWeekList() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<String> list = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();

        // 获取本周第一天（默认为周日）
        int firstDayOfWeek = calendar.getFirstDayOfWeek();
        calendar.set(Calendar.DAY_OF_WEEK, firstDayOfWeek + 1);

        list.add(sdf.format(calendar.getTime()));
        // 遍历本周剩余的日期
        for (int i = 1; i < 7; i++) {
            calendar.add(Calendar.DAY_OF_WEEK, 1); // 增加天数
            Date date = calendar.getTime();
            list.add(sdf.format(date));
        }
        return list;
    }

    //两个日期之间所有天数
    public static List<String> getDateList(Date start, Date end) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        // 设置起始日期
        calendar.setTime(start);
        Date startDate = calendar.getTime();
        // 设置结束日期
        calendar.setTime(end);
        Date endDate = calendar.getTime();
        // 获取两个日期之间的所有日期
        List<String> dateList = new ArrayList<>();
        calendar.setTime(startDate);
        while (!calendar.getTime().after(endDate)) {
            dateList.add(dateFormat.format(calendar.getTime()));
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        return dateList;
    }

    //两个月份之间间所有月
    public static List<String> getMonthList(Date start, Date end) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
        Calendar calendar = Calendar.getInstance();
        // 设置起始日期
        calendar.setTime(start);
        Date startDate = calendar.getTime();
        // 设置结束日期
        calendar.setTime(end);
        Date endDate = calendar.getTime();
        // 获取两个日期之间的所有日期
        List<String> dateList = new ArrayList<>();
        calendar.setTime(startDate);
        while (!calendar.getTime().after(endDate)) {
            dateList.add(dateFormat.format(calendar.getTime()));
            calendar.add(Calendar.MONTH, 1);
        }
        return dateList;
    }

    //两个年份之间间所有年
    public static List<String> getYearList(Date start, Date end) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");
        Calendar calendar = Calendar.getInstance();
        // 设置起始日期
        calendar.setTime(start);
        Date startDate = calendar.getTime();
        // 设置结束日期
        calendar.setTime(end);
        Date endDate = calendar.getTime();
        // 获取两个日期之间的所有日期
        List<String> dateList = new ArrayList<>();
        calendar.setTime(startDate);
        while (!calendar.getTime().after(endDate)) {
            dateList.add(dateFormat.format(calendar.getTime()));
            calendar.add(Calendar.YEAR, 1);
        }
        return dateList;
    }

    public static Map<String, String> getMonthStartEnd() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Map<String, String> map = new HashMap<>();
        Calendar calendar = Calendar.getInstance();

        calendar.set(Calendar.DAY_OF_MONTH, 1);
        Date firstDayOfMonth = calendar.getTime();

        calendar.add(Calendar.MONTH, 1);  // 设置为下个月
        calendar.set(Calendar.DAY_OF_MONTH, 1);  // 设置为下个月的第一天
        calendar.add(Calendar.DAY_OF_MONTH, -1);  // 回到当前月的最后一天
        Date lastDayOfMonth = calendar.getTime();

        map.put("first", sdf.format(firstDayOfMonth));
        map.put("end", sdf.format(lastDayOfMonth));
        return map;
    }

    /**
     * 比较两个日期的前后
     *
     * @param date1
     * @param date2
     * @return 如果date1在date2之前 则返回true
     */
    public static Boolean compareDate(Date date1, Date date2) {
        int status = date1.compareTo(date2);
        return status <= 0;
    }

    /**
     * 比较当前日期和传递日期的前后
     *
     * @param date1
     * @return 如果date1在当前日期之前 则返回true
     */
    public static Boolean compareDateNow(Date date1) {
        Date date2 = new Date();
        return compareDate(date1, date2);
    }


    /**
     * 获取两个时间之前时间差
     *
     * @param startDate
     * @param endDate
     * @return hh:mm:ss
     */
    public static String formatTimeDifference(Date startDate, Date endDate) {
        // 获取时间差，单位毫秒
        long diffInMillis = endDate.getTime() - startDate.getTime();
        if (diffInMillis < 0) {
            diffInMillis = -diffInMillis;  // 取绝对值
        }

        long totalSeconds = diffInMillis / 1000;
        long seconds = totalSeconds % 60;
        long totalMinutes = totalSeconds / 60;
        long minutes = totalMinutes % 60;
        long totalHours = totalMinutes / 60;

        // 格式化 hhh:mm:ss
        return String.format("%d:%02d:%02d", totalHours, minutes, seconds);
    }

    /**
     * 获取季度
     *
     * @param date
     * @return data所在的季度
     */
    public static int getQuarter(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        int month = calendar.get(Calendar.MONTH) + 1;  // 注意：Calendar.MONTH是0-11

        if (month >= 1 && month <= 3) {
            return 1;
        } else if (month >= 4 && month <= 6) {
            return 2;
        } else if (month >= 7 && month <= 9) {
            return 3;
        } else {
            return 4;
        }
    }


    /**
     * 根据传入的Date，返回对应的英文星期几（小写）
     *
     * @param date java.util.Date类型日期
     * @return 星期几英文小写，如 monday、tuesday
     */
    public static Integer getWeekday(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("date不能为空");
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 周日=1，周一=2，... 周六=7

        return (dayOfWeek + 5) % 7;
    }
}
